package test;

//  This code uses JavaCV to capture and display camera image, translated into bi-color images ,
// then find contour and bound of contour  in range of red color(HSV model Color) 

import java.awt.event.*;

import com.googlecode.javacpp.Loader;
import com.googlecode.javacv.*;
import com.googlecode.javacv.cpp.opencv_core.CvContour;
import com.googlecode.javacv.cpp.opencv_core.CvMat;
import com.googlecode.javacv.cpp.opencv_core.CvPoint;
import com.googlecode.javacv.cpp.opencv_core.CvScalar;
import com.googlecode.javacv.cpp.opencv_core.CvSeq;

import static com.googlecode.javacv.cpp.opencv_core.*;
import static com.googlecode.javacv.cpp.opencv_highgui.*;
import static com.googlecode.javacv.cpp.opencv_imgproc.*;

public class Demo {
	private static volatile boolean isRunning = true;

	public static void main(String[] args) throws Exception {
		// HSV First 3 are HSV value (value test by me)
		// CvScalar hsv_min = new CvScalar(132, 100, 0, 0);
		// CvScalar hsv_max = new CvScalar(179, 255, 255, 0);

		// HSV value by Andol
		CvScalar hsv_min = new CvScalar(0, 30, 80, 0);
		CvScalar hsv_max = new CvScalar(20, 150, 255, 0);

		// Images
		IplImage frame, hsv_image, hsv_mask, hsv_edge;

		// Memmory Storage
		CvMemStorage storage;
		CvMemStorage dftStorage;
		CvMemStorage minStorage;
		CvMemStorage defectStorage;

		// CvSeq
		CvSeq contours;
		CvSeq bigger_contours;

		CvConvexityDefect defectArray;

		// CvFont

		System.out.println("Starting OpenCV...");

		// Init
		CanvasFrame canvas = new CanvasFrame("Threshold");
		CanvasFrame canvas_2 = new CanvasFrame("Canvas 2");
		CanvasFrame threshCanvas = new CanvasFrame("Threshold+ open morp");

		storage = CvMemStorage.create();
		dftStorage = CvMemStorage.create();
		minStorage = CvMemStorage.create();
		defectStorage = cvCreateMemStorage(0);

		canvas.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				isRunning = false;
			}
		});

		System.out.println("Starting frame grabber...");
		OpenCVFrameGrabber grabber = new OpenCVFrameGrabber(CV_CAP_ANY);

		grabber.start();

		frame = grabber.grab();
		hsv_image = IplImage.create(frame.width(), frame.height(), 8, 3);
		hsv_mask = IplImage.create(frame.width(), frame.height(), 8, 1);
		hsv_edge = IplImage.create(frame.width(), frame.height(), 8, 1);

		System.out.println("Frame Resolution :" + frame.width() + "*"
				+ frame.height());

		while (isRunning) {
			if ((frame = grabber.grab()) == null)
				break;

			// Change Color Domain
			cvCvtColor(frame, hsv_image, CV_BGR2HSV);

			// Select Color in Range
			cvInRangeS(hsv_image, hsv_min, hsv_max, hsv_mask);

			cvSmooth(hsv_mask, hsv_mask, CV_MEDIAN, 27, 0, 0, 0);
			// cvMorphologyEx(hsv_mask, hsv_mask, null, null, CV_MOP_OPEN, 1);
			cvCanny(hsv_mask, hsv_edge, 1, 3, 5);
			// !END THRESHOLD

			// Find Contour
			contours = new CvSeq(null);
			cvFindContours(hsv_edge, storage, contours,
					Loader.sizeof(CvContour.class), CV_RETR_LIST,
					CV_CHAIN_APPROX_SIMPLE);

			bigger_contours = new CvSeq(null);

			// Find BigBox
			double result = 0, result2 = 0;
			while (contours != null && !contours.isNull()) {
				result = Math.abs(cvContourArea(contours, CV_WHOLE_SEQ, 0));
				if (result > result2) {
					result2 = result;
					bigger_contours = contours;

				}
				contours = contours.h_next();
			}

			// DrawBox Around Contour
			if (bigger_contours != null && !bigger_contours.isNull()) {
				CvRect rect = cvBoundingRect(bigger_contours, 0);
				cvRectangle(frame, cvPoint(rect.x(), rect.y() + rect.height()),
						cvPoint(rect.x() + rect.width(), rect.y()),
						CV_RGB(200, 0, 200), 5, 8, 0);

				int checkcxt = cvCheckContourConvexity(bigger_contours);
				System.out.println(checkcxt);

				// draw hull line

				CvSeq hull = cvConvexHull2(bigger_contours, null, CV_CLOCKWISE,
						0);

				CvMat hullMatrix = cvCreateMat(1, bigger_contours.total(),
						CV_32SC1);

				CvPoint pointArray = new CvPoint(bigger_contours.total());
				cvCvtSeqToArray(bigger_contours, pointArray, CV_WHOLE_SEQ);
				cvConvexHull2(bigger_contours, hullMatrix,
						CV_COUNTER_CLOCKWISE, 0);

				int hullCount = hullMatrix.cols();
				System.out.println("Hull Pos net.:" + hullCount);
				CvPoint pt = pointArray.position((int) hullMatrix
						.get(hullCount - 1));

				CvPoint pt0 = new CvPoint(pt.x(), pt.y());
				for (int i = 0; i < hullCount; i++) {
					pt = pointArray.position((int) hullMatrix.get(i));
					System.out.println("@Position (" + i + ") >>"
							+ hullMatrix.get(i) + ":Point: X-" + pt.x() + ":Y-"
							+ pt.y());
					// cvDrawCircle(src_image, pt, 5, CvScalar.BLUE, -1, 8, 0);
					cvLine(frame, pt0, pt, CV_RGB(255, 255, 0), 3, CV_AA, 0);
					pt0 = new CvPoint(pt.x(), pt.y());
				}

				// Findind An Defect

				CvSeq defectSeq = cvConvexityDefects(bigger_contours,
						hullMatrix, defectStorage);
				defectArray = new CvConvexityDefect(defectSeq.total());// create
																		// Array
																		// as
																		// Defect
																		// Array
				cvCvtSeqToArray(defectSeq, defectArray, CV_WHOLE_SEQ);

				int defectCount = defectSeq.total();
				for (int i = 0; i < defectCount; i++) {
					cvLine(frame, defectArray.position(i).start(), defectArray
							.position(i).depth_point(), CV_RGB(0, 0, 255), 1,
							CV_AA, 0);
					cvDrawCircle(frame, defectArray.position(i).start(), 5,
							CvScalar.GREEN, -1, 8, 0);
					cvDrawCircle(frame, defectArray.position(i).depth_point(),
							5, CvScalar.GREEN, -1, 8, 0);
					cvLine(frame, defectArray.position(i).depth_point(),
							defectArray.position(i).end(), CV_RGB(0, 0, 255),
							1, CV_AA, 0);

				}

				CvBox2D box = cvMinAreaRect2(bigger_contours, minStorage);

				cvCircle(
						frame,
						cvPoint((int) box.center().x(), (int) box.center().y()),
						3, CvScalar.BLACK, 2, 8, 0);

				cvEllipse(
						frame,
						cvPoint((int) box.center().x(), (int) box.center().y()),
						cvSize((int) box.size().height() / 2, (int) box.size()
								.width() / 2), box.angle(), 0, 360,
						CvScalar.RED, 2, 8, 0);

			}

			// Draw Images on Frames
			canvas.showImage(frame);
			threshCanvas.showImage(hsv_mask);
			canvas_2.showImage(hsv_edge);
		}
		grabber.stop();
		canvas.dispose();
		threshCanvas.dispose();
		canvas_2.dispose();

	} // end of main()

} // end of Demo class